﻿//  Copyright (c) 2011 Ray Liang (http://www.dotnetage.com)
//  Licensed MIT: http://www.opensource.org/licenses/mit-license.php

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Threading;

namespace DNA.Mvc.Management
{
    /// <summary>
    /// Provides tracing services through a set of <see cref="TraceListener"/>s.
    /// </summary>
    public class LogSource : IDisposable
    {
        public List<TraceListener> listeners = null;

        public LogSource(string name, IEnumerable<TraceListener> listeners, bool autoFlush = true, SourceLevels level = SourceLevels.All)
        {
            this.listeners = new List<TraceListener>(listeners);
            this.AutoFlush = autoFlush;
            this.Level = level;
            this.Name = name;
        }

        /// <summary>
        /// Gets the name for the <see cref="LogSource"/> instance.
        /// </summary>
        public string Name { get; private set; }

        /// <summary>
        /// Gets or sets the <see cref="AutoFlush"/> values for the <see cref="LogSource"/> instance.
        /// </summary>
        public bool AutoFlush { get; set; }

        /// <summary>
        /// Gets the <see cref="SourceLevels"/> values at which to trace for the <see cref="LogSource"/> instance.
        /// </summary>
        public SourceLevels Level { get; private set; }

        /// <summary>
        /// Writes trace data to the trace listeners in the <see cref="LogSource.Listeners"/> collection using the specified 
        /// event type, event identifier, and trace data. 
        /// </summary>
        /// <param name="eventType">The value that specifies the type of event that caused the trace.</param>
        /// <param name="id">A numeric identifier for the event.</param>
        /// <param name="logEntry">The <see cref="LogEntry"/> to trace.</param>
        public void TraceData(TraceEventType eventType, int id, EventLogEntry logEntry)
        {
            TraceData(eventType, id, logEntry, new TraceEventCache());
        }

        internal void TraceData(TraceEventType eventType, int id, EventLogEntry logEntry, TraceEventCache traceEventCache)
        {
            if (!ShouldTrace(eventType)) return;

            bool isTransfer = logEntry.Severity == TraceEventType.Transfer && logEntry.RelatedActivityId != null;

            foreach (TraceListener listener in listeners)
            {
                try
                {
                    if (!listener.IsThreadSafe) Monitor.Enter(listener);

                    if (!isTransfer)
                    {
                        listener.TraceData(traceEventCache, Name, eventType, id, logEntry);
                    }
                    else
                    {
                        listener.TraceTransfer(traceEventCache, Name, id, logEntry.Message, logEntry.RelatedActivityId);
                    }

                    if (this.AutoFlush)
                    {
                        listener.Flush();
                    }
                }
                finally
                {
                    if (!listener.IsThreadSafe) Monitor.Exit(listener);
                }
            }
        }

        /// <summary>
        /// Releases the resources used by the <see cref="LogSource"/>.
        /// </summary>
        public void Dispose()
        {
            foreach (TraceListener listener in listeners)
            {
                listener.Dispose();
            }
        }

        private bool ShouldTrace(TraceEventType eventType)
        {
            return ((((TraceEventType)Level) & eventType) != (TraceEventType)0);
        }
    }
}
